<template>
  <canvas id="canvas"
          ref="canvas"></canvas>
</template>

<script lang="ts"
        setup>
import {
  AmbientLight,
  AxesHelper,
  Clock,
  EquirectangularReflectionMapping,
  Mesh,
  MeshPhongMaterial,
  MeshStandardMaterial,
  PerspectiveCamera,
  Renderer,
  Scene,
  SphereGeometry,
  SpotLight,
  TextureLoader,
  WebGLRenderer
} from 'three'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
import {onMounted, ref} from 'vue'

let canvas = ref<HTMLCanvasElement>()

let scene: Scene
let camera: PerspectiveCamera
let renderer: Renderer
let textureLoader = new TextureLoader()
let clock = new Clock()

let earthModel: Mesh
let moonModel: Mesh

const EARTH_RADIUS = 2.5
const MOON_RADIUS = 0.27
const EARTH_MOON_DISTANCE = 3.5

onMounted(() => {
  init()
  // copilot()

  initLight()
  initSceneBackground()
  initEarthModel()
  initMoonModel()

  render()
})

// 初始化变量
function init() {
  scene = new Scene()
  camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight)
  camera.position.set(6, 8, 6)
  camera.lookAt(0, 0, 0)
  scene.add(camera)
  let orbitControls = new OrbitControls(camera, canvas.value)
  orbitControls.maxDistance = 20
  renderer = new WebGLRenderer({canvas: canvas.value})
  renderer.setSize(window.innerWidth, window.innerHeight)

  window.onresize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
  }
}

// 辅助工具
function copilot() {
  let axesHelper = new AxesHelper(5)
  scene.add(axesHelper)
}

// 初始化光源
function initLight() {
  let spotLight = new SpotLight(0xffffff, 1.5)
  spotLight.position.set(0, 5, 10)
  scene.add(spotLight)

  let ambientLight = new AmbientLight(0xffffff, 0.6)
  scene.add(ambientLight)
}

// 初始化场景背景
function initSceneBackground() {
  let bg = textureLoader.load('/textures/starts.jpg')
  // 设置为球面背景
  bg.mapping = EquirectangularReflectionMapping
  scene.background = bg
  scene.environment = bg
}

// 初始化地球模型
function initEarthModel() {
  let sphereGeometry = new SphereGeometry(EARTH_RADIUS, 50, 50)
  let meshStandardMaterial = new MeshPhongMaterial({
    map: textureLoader.load('/textures/earth/earth_atmos_2048.jpg'),
    normalMap: textureLoader.load('/textures/earth/earth_normal_2048.jpg'),
    specularMap: textureLoader.load('/textures/earth/earth_specular_2048.jpg')
  })
  earthModel = new Mesh(sphereGeometry, meshStandardMaterial)
  scene.add(earthModel)
}

// 初始化月球模型
function initMoonModel() {
  let sphereGeometry = new SphereGeometry(MOON_RADIUS, 16, 16)
  let meshStandardMaterial = new MeshStandardMaterial({
    map: textureLoader.load('/textures/moon/moon_1024.jpg')
  })
  moonModel = new Mesh(sphereGeometry, meshStandardMaterial)
  moonModel.position.z = EARTH_MOON_DISTANCE
  scene.add(moonModel)
}

let lastTime = 0

// 渲染函数
function render() {
  requestAnimationFrame(render)

  let time = clock.getElapsedTime()
  // 月球公转
  let x = Math.sin(time) * EARTH_MOON_DISTANCE
  moonModel.position.x = x
  // x^2 + z^2 = EARTH_MOON_DISTANCE^2
  moonModel.position.z = Math.sqrt(EARTH_MOON_DISTANCE * EARTH_MOON_DISTANCE - x * x) * (Math.cos(time) >= 0 ? 1 : -1)
  // 月球自转
  moonModel.rotateY((time - lastTime) * Math.PI / 2)

  // 地球自转
  earthModel.rotateY((time - lastTime) * Math.PI / 15)

  lastTime = time
  renderer.render(scene, camera)
}


</script>

<style lang="scss"
       scoped>

</style>